﻿using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
using System.Collections;
using System.IO.MemoryMappedFiles;
using System.Text;
using System.IO;

public partial class gbr
{
    public struct FilePart_Row
    {
        public Int64 pk;
        public StringBuilder str;
    }
    [Microsoft.SqlServer.Server.SqlFunction(FillRowMethodName = "GetFilePart_Fill")]
    public static IEnumerator GetFilePart(string fn, long offset, long length, long bufferLength)
    {
        FilePart_Row row;
        row.pk = 1;
        row.str = new StringBuilder();
        long lLocalStart = offset;
        long lEnd = new FileInfo(fn).Length;
        if (lEnd > offset + length && length > offset)
            lEnd = offset + length;
        using (MemoryMappedFile mmf = MemoryMappedFile.CreateFromFile(fn))
        {
            for (long lLocalEnd = lLocalStart + bufferLength; lLocalStart < lEnd; lLocalEnd += bufferLength)
            {
                if (lLocalEnd > lEnd)
                {
                    bufferLength -= lEnd + lLocalEnd - 1;
                    lLocalEnd = lEnd;
                }
                using (var accessor = mmf.CreateViewAccessor(lLocalStart, lLocalEnd - lLocalStart + 1))
                {
                    byte b;
                    for (long i = 0; i < bufferLength; i++)
                    {
                        accessor.Read(i, out b);
                        if (b >= 32)
                            row.str.Append((char)b);
                        if (b == 13 || row.str.Length == 4000)
                        {
                            yield return row;
                            row.str.Length = 0;
                            row.pk++;
                        }
                    }
                }
                lLocalStart = lLocalEnd;
            }
        }
        if (row.str.Length > 0)
            yield return row;
        
    }

    public static void GetFilePart_Fill(object row, out Int64 pk, out string str)
    {
        FilePart_Row r = (FilePart_Row)row;
        pk = r.pk;
        str = r.str.ToString();
    }
};